import { SetupContext, defineComponent, onMounted, ref, watch } from 'vue';
import { DayViewPropsType, dayViewProps } from './day-view.props';
import { useCompare } from '../../composition/use-compare';
import { DateObject } from '../../types/common';
import './day-view.css';
import { DayInCalendar } from '../../types/calendar';
import { ItemInSchedule, ScheduleEvent, TimeInSchedule } from '../../types/schedule';

export default defineComponent({
    name: 'FCalendarDayView',
    props: dayViewProps,
    emits: [],
    setup(props: DayViewPropsType, context: SetupContext) {
        const dayViewContentRef = ref<any>();
        const primaryDayViewContentRef = ref<any>();
        const dayInWeek = ref<string>(props.dayInWeek);
        const day = ref<DayInCalendar>(props.day as DayInCalendar);
        const enableMarkCurrent = ref(props.enableMarkCurrent);
        const events = ref<ScheduleEvent[]>(props.events);

        const items = ref<TimeInSchedule[]>([]);

        const { equal } = useCompare();

        function buildViewItemCell(time: DateObject) {
            const cellDate: DateObject = {
                year: day.value.date.year,
                month: day.value.date.month,
                day: day.value.date.day,
                hour: time.hour,
                minute: time.minute,
                second: time.second
            };
            const cellEvents = events.value.filter((eventItem: ScheduleEvent) => equal(eventItem.starts, cellDate)) as ScheduleEvent[];
            return [
                {
                    day: cellDate,
                    events: cellEvents
                }
            ];
        }

        function loadCalendarViewItems() {
            const result: TimeInSchedule[] = [];
            for (let i = 0; i < 24; i++) {
                const oClock = { hour: i, minute: 0, second: 0 };
                const halfPast = { hour: i, minute: 30, second: 0 };
                const oClockCells = buildViewItemCell(oClock);
                const halfPastCells = buildViewItemCell(halfPast);
                result.push({
                    time: oClock,
                    events: oClockCells,
                    title: i > 0 ? `${i}:00` : '',
                    part: 'upper'
                });
                result.push({
                    time: halfPast,
                    events: halfPastCells,
                    title: `${i}:30`,
                    part: 'lower'
                });
            }
            items.value = result;
        }

        loadCalendarViewItems();
        watch(
            () => props.day,
            () => {
                day.value = props.day as DayInCalendar;
                loadCalendarViewItems();
            }
        );
        watch(
            () => props.events,
            () => {
                events.value = props.events;
                loadCalendarViewItems();
            }
        );

        const dayClass = (currentDay: DayInCalendar) => {
            const shouldMarkCurrentDay = currentDay.isCurrent && enableMarkCurrent.value;
            const classObject = {
                'f-calendar-day-view-date': true,
                'f-calendar-day-view-current': shouldMarkCurrentDay
            } as Record<string, boolean>;
            return classObject;
        };

        function renderHeader() {
            return (
                <div class="f-calendar-day-view-header">
                    <div class="f-calendar-day-view-header-corner"></div>
                    <div class="f-calendar-day-view-header-primary">
                        <div class="f-calendar-day-view-header-columns">
                            <div class="f-calendar-day-view-header-cell">
                                <div class={dayClass(day.value)}>{day.value.date.day}</div>
                                <span>{dayInWeek.value}</span>
                            </div>
                        </div>
                    </div>
                </div>
            );
        }

        function renderSidebar() {
            return (
                <div class="f-calendar-day-view-content-side">
                    <div class="f-calendar-side">
                        {items.value.map((timeItem: TimeInSchedule) => {
                            return (
                                <div class="f-calendar-side-row">
                                    <div class="f-calendar-side-row-number">{timeItem.part === 'upper' ? timeItem.title : ''}</div>
                                </div>
                            );
                        })}
                    </div>
                </div>
            );
        }

        function timeItemClass(timeItem: TimeInSchedule) {
            const classObject = {
                'f-calendar-day-view-item': true,
                'f-calendar-day-view-item-upper': timeItem.part === 'upper',
                'f-calendar-day-view-item-lower': timeItem.part === 'lower'
            } as Record<string, boolean>;
            return classObject;
        }

        function eventItemStyle(eventItem: ScheduleEvent) {
            const height = 44;
            const marginBottom = 2;
            const marginTop = 2;
            const borderBottom = 1;
            const borderTop = 1;
            const start = (eventItem.starts.hour || 0) + (eventItem.starts.minute || 0) / 60;
            const end = (eventItem.ends.hour || 0) + (eventItem.ends.minute || 0) / 60;
            const actualHeight = height * (end - start) - marginTop - marginBottom - borderTop - borderBottom;
            const styleObject = {
                height: `${actualHeight}px`
            } as Record<string, any>;
            return styleObject;
        }

        function renderGridData() {
            return items.value.map((timeItem: TimeInSchedule) => {
                return (
                    <div class={timeItemClass(timeItem)}>
                        {timeItem.events.map((item: ItemInSchedule) => {
                            return (
                                <div class="f-calendar-day-view-item-cell">
                                    {item.events.length > 0 &&
                                        item.events.map((eventItem: ScheduleEvent) => {
                                            return (
                                                <div class="f-calendar-event" style={eventItemStyle(eventItem)}>
                                                    {eventItem.title}
                                                </div>
                                            );
                                        })}
                                </div>
                            );
                        })}
                    </div>
                );
            });
        }

        function renderDataArea() {
            return (
                <div ref={primaryDayViewContentRef} class="f-calendar-content-primary">
                    <div class="f-calendar-content-data">{renderGridData()}</div>
                </div>
            );
        }

        onMounted(() => {
            if (dayViewContentRef.value) {
                dayViewContentRef.value.scrollTo(0, 250);
            }
        });

        return () => {
            return (
                <div class="f-calendar-day-view">
                    {renderHeader()}
                    <div class="f-calendar-day-view-content" ref={dayViewContentRef}>
                        {renderSidebar()}
                        {renderDataArea()}
                    </div>
                </div>
            );
        };
    }
});
